<template>
    <j-modal
        :mask-closable="false"
        title="导入物模型"
        destroy-on-close
        v-model:visible="_visible"
        @cancel="close"
        @ok="handleImport"
        :confirm-loading="loading"
    >
        <div class="import-content">
            <p class="import-tip">
                <AIcon
                    type="ExclamationCircleOutlined"
                    style="margin-right: 5px"
                />
                <template v-if="type === 'product'">
                    导入的物模型会覆盖原来的属性、功能、事件、标签，请谨慎操作。
                </template>
                <template v-else>
                    导入时会根据标识跳过继承自产品物模型的属性、功能、事件、标签。
                </template>
            </p>
        </div>
        <j-form layout="vertical" ref="formRef" :model="formModel">
            <j-form-item
                v-if="type === 'product'"
                label="导入方式"
                name="type"
                :rules="[
                    {
                        required: true,
                        message: '请选择导入方式',
                    },
                ]"
            >
                <j-select v-model:value="formModel.type">
                    <j-select-option value="copy">拷贝产品</j-select-option>
                    <j-select-option value="import">导入物模型</j-select-option>
                </j-select>
            </j-form-item>
            <j-form-item
                label="选择产品"
                :rules="[
                    {
                        required: true,
                        message: '请选择产品',
                    },
                ]"
                name="copy"
                v-if="formModel.type === 'copy'"
            >
                <j-select
                    :options="productList"
                    v-model:value="formModel.copy"
                    option-filter-prop="label"
                    placeholder="请选择产品"
                    showSearch
                ></j-select>
            </j-form-item>
            <j-form-item
                label="物模型类型"
                :rules="[
                    {
                        required: true,
                        message: '请选择物模型类型',
                    },
                ]"
                name="metadata"
                v-if="type === 'device' || formModel.type === 'import'"
            >
                <j-select v-model:value="formModel.metadata">
                    <j-select-option value="jetlinks"
                        >Jetlinks物模型</j-select-option
                    >
                    <j-select-option value="alink"
                        >阿里云物模型TSL</j-select-option
                    >
                </j-select>
            </j-form-item>
            <j-form-item
                label="导入类型"
                :rules="[
                    {
                        required: true,
                        message: '请选择导入类型',
                    },
                ]"
                name="metadataType"
                v-if="type === 'device' || formModel.type === 'import'"
            >
                <j-select v-model:value="formModel.metadataType" @change="formModel.import = undefined">
                    <j-select-option value="file">文件上传</j-select-option>
                    <j-select-option value="script">脚本</j-select-option>
                </j-select>
            </j-form-item>
            <j-form-item
                v-if="
                    formModel.type === 'import' &&
                    formModel.metadataType === 'file'
                "
                label="文件上传"
                name="import"
                :rules="[
                    {
                        required: true,
                        message: '请上传文件',
                    },
                ]"
            >
                <!-- <j-input v-model:value="formModel.upload">
                    <template #addonAfter>
                        <j-upload
                            v-model:file-list="fileList"
                            :before-upload="beforeUpload"
                            accept=".json"
                            :show-upload-list="false"
                            :action="FILE_UPLOAD"
                            @change="fileChange"
                            :headers="{ 'X-Access-Token': getToken() }"
                        >
                            <AIcon
                                type="UploadOutlined"
                                class="upload-button"
                            />
                        </j-upload>
                    </template>
                </j-input> -->
                <j-upload
                    v-model:file-list="fileList"
                    :before-upload="beforeUpload"
                    accept=".json"
                    :show-upload-list="false"
                    :action="FILE_UPLOAD"
                    @change="fileChange"
                    :headers="{ 'X-Access-Token': getToken() }"
                >
                    <j-button>
                        <template #icon><AIcon type="UploadOutlined" /></template>
                        上传文件
                    </j-button>
                </j-upload>
                <div style="margin-left: 10px; color: rgba(0, 0, 0, .6);">支持扩展名：.json</div>
            </j-form-item>
            <j-form-item
                :rules="[
                    {
                        required: true,
                        message: '请输入物模型',
                    },
                ]"
                name="import"
                v-if="
                    (type === 'device' || formModel.type === 'import') &&
                    formModel.metadataType === 'script'
                "
            >
                <template #label>
                    <j-space>
                        物模型
                        <j-tooltip title="在线编辑器中编写物模型脚本">
                            <AIcon
                                type="QuestionCircleOutlined"
                                style="color: rgb(136, 136, 136)"
                            />
                        </j-tooltip>
                    </j-space>
                </template>
                <JMonacoEditor
                    v-model:modelValue="formModel.import"
                    theme="vs"
                    style="height: 300px"
                    lang="json"
                ></JMonacoEditor>
            </j-form-item>
        </j-form>
    </j-modal>
</template>
<script setup lang="ts" name="Import">
import { saveMetadata } from '@/api/device/instance';
import {
    queryNoPagingPost,
    convertMetadata,
    modify,
} from '@/api/device/product';
import type { DefaultOptionType } from 'ant-design-vue/es/select';
import type {
    UploadProps,
    UploadFile,
    UploadChangeParam,
} from 'ant-design-vue/es';
import type { DeviceMetadata } from '@/views/device/Product/typings';
import { useInstanceStore } from '@/store/instance';
import { useProductStore } from '@/store/product';
import { FILE_UPLOAD } from '@/api/comm';
import { getToken, onlyMessage } from '@/utils/comm';
import { useMetadataStore } from '@/store/metadata';
import { omit } from 'lodash-es';
import { Modal } from 'jetlinks-ui-components';

const route = useRoute();
const instanceStore = useInstanceStore();
const productStore = useProductStore();

interface Props {
    visible: boolean;
    type: 'device' | 'product';
}
interface Emits {
    (e: 'update:visible', data: boolean): void;
    (e: 'submit', data: any): void;
}
const props = defineProps<Props>();
const emits = defineEmits<Emits>();
const loading = ref(false);

const _visible = computed({
    get: () => {
        return props.visible;
    },
    set: (val: any) => {
        emits('update:visible', val);
    },
});

const close = () => {
    emits('update:visible', false);
};

/** form表单 */
const formModel = reactive<Record<string, any>>({
    type: 'import',
    metadata: 'jetlinks',
    metadataType: 'script',
});
// const { validate, validateInfos } = useForm(formModel, rules);
const fileList = ref<UploadFile[]>([]);
const hasVirtualRule = ref(false);
const formRef = ref();

const productList = ref<DefaultOptionType[]>([]);

const loadData = async () => {
    const { id } = route.params || {};
    const product = (await queryNoPagingPost({
        paging: false,
        sorts: [{ name: 'createTime', order: 'desc' }],
        terms: [{ column: 'id$not', value: id }],
    })) as any;
    productList.value = product.result
        .filter((i: any) => i?.metadata)
        .map((item: any) => ({
            label: item.name,
            value: item.metadata,
            key: item.id,
        })) as DefaultOptionType[];
};
loadData();

// const propertiesSet = new Set(['id','name','expands','valueType']);

// const handleMadeDataNull = (data:any) =>{
//    return data?.properties?.some?.((item:any,index:number)=>{
//                 if(!item?.id){
//                     onlyMessage(`属性定义第${index + 1}个数组中缺失id属性`,'error');
//                     return true
//                 }
//                 if(!item?.name){
//                     onlyMessage(`属性定义第${index + 1}个数组中缺失name属性`,'error');
//                     return 
//                 }
//                 if(!item?.expands?.source){
//                     onlyMessage(`属性定义第${index + 1}个数组中缺失expands.source属性`,'error');
//                     return 
//                 }
               
//                 if((item?.expands?.source === 'device' ||    item?.expands?.source === 'rule') && !item?.expands?.type){
//                     onlyMessage(`属性定义第${index + 1}个数组中缺失type属性`,'error');
//                     return
//                 }           
//         }) || false
// }
const requiredCheck = (data:any) =>{
    let check:boolean = false;
    if(data?.properties && !check){
        data.properties.some((item:any,index:number)=>{
                if(!item?.id){
                    onlyMessage(`属性定义第${index + 1}个数组中缺失id属性`,'error');
                    check = true
                    return 
                }
                if(!item?.name){
                    onlyMessage(`属性定义第${index + 1}个数组中缺失name属性`,'error');
                    check = true
                    return 
                }
                if(!item?.valueType?.type){
                    onlyMessage(`标签定义第${index + 1}个数组中缺失valueType.type属性`,'error');
                    check = true
                    return
                }
                if(!item?.expands?.source){
                    onlyMessage(`属性定义第${index + 1}个数组中缺失expands.source属性`,'error');
                    check = true
                    return 
                }
               
                if((item?.expands?.source === 'device' ||    item?.expands?.source === 'rule') && !item?.expands?.type){
                    onlyMessage(`属性定义第${index + 1}个数组中缺失type属性`,'error');
                    check = true
                    return
                }           
        })
    }
    if(data?.functions  && !check){
        data?.functions.forEach((item:any,index:number)=>{
            if(!item?.id){
                    onlyMessage(`方法定义第${index + 1}个数组中缺失id属性`,'error');
                    check = true
                    return
                }
            if(!item?.name){
                    onlyMessage(`方法定义第${index + 1}个数组中缺失name属性`,'error');
                    check = true
                    return
                } 
            if(!item?.async && item?.async !== false){
                    onlyMessage(`方法定义第${index + 1}个数组中缺失async属性`,'error');
                    check = true
                    return
            }
        })
    }
    if(data?.events && !check){
        data?.events.forEach((item:any,index:number)=>{
            if(!item?.id){
                    onlyMessage(`事件定义第${index + 1}个数组中缺失id属性`,'error');
                    check = true
                    return
                }
            if(!item?.name){
                    onlyMessage(`事件定义第${index + 1}个数组中缺失name属性`,'error');
                    check = true
                    return
                }
            if(!item?.async && item?.async !== false){
                    onlyMessage(`事件定义第${index + 1}个数组中缺失async属性`,'error');
                    check = true
                    return
            }
            if(!item?.valueType?.type){
                    onlyMessage(`事件定义第${index + 1}个数组中缺失valueType.type属性`,'error');
                    check = true
                    return
            }
            if(!item?.expands?.level){
                    onlyMessage(`事件定义第${index + 1}个数组中缺失expands.level属性`,'error');
                    check = true
                    return
            }
            if(!check){
                if(item?.valueType?.properties){
                    item?.valueType?.properties.forEach((i:any,number:number)=>{
                if(!i?.id){
                    onlyMessage(`事件定义第${index + 1}个数组中缺失valueType.properties数组第${number+1}项的id属性`,'error');
                    check = true
                    return
                }
                if(!i?.name){
                    onlyMessage(`事件定义第${index + 1}个数组中缺失valueType.properties数组第${number+1}项的name属性`,'error');
                    check = true
                    return
                }
                if(!i?.valueType?.type){
                    onlyMessage(`事件定义第${index + 1}个数组中缺失valueType.properties数组第${number+1}项的valueType.type属性`,'error');
                    check = true
                    return
                }   
                    })   
                }else{
                    onlyMessage(`事件定义第${index + 1}个数组中缺失valueType.properties数组`,'error');
                    check = true
                    return
                } 
            }
        })
    }
    if(data?.tags && !check){
        data?.tags.forEach((item:any,index:number)=>{
            if(!item?.id){
                    onlyMessage(`标签定义第${index + 1}个数组中缺失id属性`,'error');
                    check = true
                    return
                }
            if(!item?.name){
                    onlyMessage(`标签定义第${index + 1}个数组中缺失name属性`,'error');
                    check = true
                    return
                } 
            if(!item?.valueType?.type){
                    onlyMessage(`标签定义第${index + 1}个数组中缺失valueType.type属性`,'error');
                    check = true
                    return
            }
            if(!item?.expands?.type){
                    onlyMessage(`标签定义第${index + 1}个数组中缺失expands.type属性`,'error');
                    check = true
                    return
            }
        })
    }
    return check
}

const aliCheck = (data:any) => {
    let check:boolean = false;
    if(data?.properties && !check){
        data.properties.some((item:any,index:number)=>{
                if(!item?.identifier){
                    onlyMessage(`属性定义第${index + 1}个数组中缺失identifier属性`,'error');
                    check = true
                    return 
                }
                if(!item?.name){
                    onlyMessage(`属性定义第${index + 1}个数组中缺失name属性`,'error');
                    check = true
                    return 
                }
                if(!item?.dataType?.type){
                    onlyMessage(`属性定义第${index + 1}个数组中缺失dataType.type属性`,'error');
                    check = true
                    return 
                }  
        })
    }
    if(data?.functions  && !check){
        data?.functions.forEach((item:any,index:number)=>{
            if(!item?.identifier){
                    onlyMessage(`方法定义第${index + 1}个数组中缺失identifier属性`,'error');
                    check = true
                    return
                }
            if(!item?.name){
                    onlyMessage(`方法定义第${index + 1}个数组中缺失name属性`,'error');
                    check = true
                    return
                } 
            if(!item?.callType){
                    onlyMessage(`方法定义第${index + 1}个数组中缺失callType属性`,'error');
                    check = true
                    return
            }
        })
    }
    if(data?.events && !check){
        data?.events.forEach((item:any,index:number)=>{
            if(!item?.identifier){
                    onlyMessage(`事件定义第${index + 1}个数组中缺失identifier属性`,'error');
                    check = true
                    return
                }
            if(!item?.name){
                    onlyMessage(`事件定义第${index + 1}个数组中缺失name属性`,'error');
                    check = true
                    return
                }
            if(!item?.type){
                    onlyMessage(`事件定义第${index + 1}个数组中缺失type属性`,'error');
                    check = true
                    return
            }
            if(!check){
                if(item?.outputData){
                    item?.outputData?.forEach((i:any,number:number)=>{
                if(!i?.identifier){
                    onlyMessage(`事件定义第${index + 1}个数组中缺失outputData数组第${number+1}项的id属性`,'error');
                    check = true
                    return
                }
                if(!i?.name){
                    onlyMessage(`事件定义第${index + 1}个数组中缺失outputData数组第${number+1}项的name属性`,'error');
                    check = true
                    return
                }
                if(!i?.dataType?.type){
                    onlyMessage(`事件定义第${index + 1}个数组中缺失outputData数组第${number+1}项的dataType.type属性`,'error');
                    check = true
                    return
                }   
                if(!i?.dataType?.specs){
                    onlyMessage(`事件定义第${index + 1}个数组中缺失outputData数组第${number+1}项的dataType.specs属性`,'error');
                    check = true
                    return
                }   
                    })   
                }else{
                    onlyMessage(`事件定义第${index + 1}个数组中缺失outputData数组`,'error');
                    check = true
                    return
                } 
            }
        })
    }
    return check
} 
const beforeUpload: UploadProps['beforeUpload'] = (file) => {
    if(file.type === 'application/json') {
        const reader = new FileReader();
        reader.readAsText(file);
        reader.onload = (json) => {
            if(json.target?.result){
                const data = JSON.parse(json.target?.result);

                let check = formModel.metadata === 'jetlinks' ? requiredCheck(data) : aliCheck(data) 
                if(!check){
                    onlyMessage('操作成功！')
                    formModel.import = json.target?.result;
                }
            } else {
                onlyMessage('文件内容不能为空', 'error')
            }
        };
    } else {
        onlyMessage('请上传json格式的文件', 'error')
    }
};
const fileChange = (info: UploadChangeParam) => {
    if (info.file.status === 'done') {
        const { response } = info.file;
        if (response.status === 200) {
            formModel.upload = response.result;
        }
    }
};

const uniqArray = (arr: any[]) => {
  const _map = new Map();
  for(let item of arr) {
    _map.set(item.id, item)
  }
  return [..._map.values()]
}

const operateLimits = (mdata: DeviceMetadata) => {
    hasVirtualRule.value = false;
    const obj: DeviceMetadata = { ...mdata };
    const old = JSON.parse((props.type === 'device' ? instanceStore.detail?.metadata : productStore.detail?.metadata) || '{}');
    const fid = instanceStore.detail?.features?.map((item) => item.id);
    const _data: DeviceMetadata = {
      properties: [],
      events: [],
      functions: [],
      tags: []
    }
    _data.properties = uniqArray([...(old?.properties || []), ...uniqArray(obj?.properties || [])])
    _data.events = uniqArray([...(old?.events || []), ...uniqArray(obj?.events || [])])
    _data.functions = uniqArray([...(old?.functions || []), ...uniqArray(obj?.functions || [])])
    _data.tags = uniqArray([...(old?.tags || []), ...uniqArray(obj?.tags || [])])

    if (fid?.includes('eventNotModifiable')) {
       _data.events = old?.events || [];
    }
    if (fid?.includes('propertyNotModifiable')) {
       _data.properties = old?.properties || [];
    }

    (_data?.properties || []).map((item) => {
        if (item.expands?.source === 'rule') {
            hasVirtualRule.value = true;
            item.expands = omit(item.expands, ['virtualRule']);
        }
        return item
    });
    return _data;
};
const metadataStore = useMetadataStore();

const handleImport = async () => {
    formRef.value.validate().then(async (data: any) => {
        const { id } = route.params || {};
        if (data.metadata === 'alink') {
            try {
                const _import = JSON.parse(data.import);
               
                loading.value = true;
                const res = await convertMetadata(
                    'from',
                    'alink',
                    _import,
                ).catch((err) => err);
                if (res.status === 200) {
                    // const metadata = operateLimits(res.result); // 导入取并集逻辑
                    const metadata = res.result
                    let result;
                    if (props?.type === 'device') {
                        result = await saveMetadata(
                            id as string,
                            metadata,
                        ).catch((err) => err);
                    } else {
                        result = await modify(id as string, {
                            id,
                            metadata: JSON.stringify(metadata),
                        }).catch((err) => err);
                    }
                    if (result.success) {
                        onlyMessage('导入成功');
                    }
                    loading.value = false;
                } else {
                    loading.value = false;
                    return;
                }
                if (props?.type === 'device') {
                    await instanceStore.refresh(id as string);
                } else {
                    await productStore.getDetail(id as string);
                }
                metadataStore.set('importMetadata', true);
                close();
            } catch (e) {
                onlyMessage(
                    e === 'error'
                        ? '物模型数据不正确'
                        : '上传json格式的物模型文件',
                    'error',
                );
            }
        } else {
            try {
                const _object = JSON.parse(
                    data[data?.type === 'copy' ? 'copy' : 'import'] ||
                        '{}',
                );
                
                if (
                    !(
                        !!_object?.properties ||
                        !!_object?.events ||
                        !!_object?.functions ||
                        !!_object?.tags
                    )
                ) {
                    onlyMessage('物模型数据不正确', 'error');
                    loading.value = false;
                    return;
                }
                const { id } = route.params || {};
                // const copyOperateLimits = operateLimits(
                //     _object as DeviceMetadata,
                // );
                // console.log(copyOperateLimits,_object); // 导入取并集逻辑
                const params = {
                    id,
                    metadata: JSON.stringify(_object),
                };
                const paramsDevice = _object;
                let resp = undefined;
                loading.value = true;
                if (props?.type === 'device') {
                    resp = await saveMetadata(id as string, paramsDevice);
                } else {
                    resp = await modify(id as string, params);
                }
                loading.value = false;
                if (resp.success) {
                    onlyMessage('导入成功');
                    if (hasVirtualRule.value) {
                        setTimeout(() => {
                            Modal.info({
                                title: '导入数据存在虚拟属性，请及时添加虚拟属性计算规则。',
                                okText: '确认',
                            });
                        }, 300);
                    }
                }
                if (props?.type === 'device') {
                    await instanceStore.refresh(id as string);
                } else {
                    await productStore.getDetail(id as string);
                }
                metadataStore.set('importMetadata', true);
                close();
            } catch (e) {
                loading.value = false;
                onlyMessage(
                    e === 'error'
                        ? '物模型数据不正确'
                        : '上传json格式的物模型文件',
                    'error',
                );
            }
        }
    });
};

// const showProduct = computed(() => formModel.type === 'copy')
</script>
<style scoped lang="less">
.import-content {
    background: rgb(236, 237, 238);

    .import-tip {
        padding: 10px;
    }
}

.upload-button {
    width: 37px;
    height: 30px;
    line-height: 30px;
    margin: 0 -11px;
}
</style>